Issue statement
PHLEGM v9 r82 correctly computes a positive-going, nonlinear 2A03 APU DAC mix, then routes it through hardcoded NES filters in sound.bi and writes same-sign PCM. The source shows no configurable NES analog output polarity and no explicit sign inversion in that path. Because the NES-001 schematic includes an inverting output stage, there is a plausible absolute electrical-polarity mismatch at the emulated output boundary.
The NES filter frequencies and coefficients are fixed in the reusable host audio code. The inspected APU-to-PCM path does not explicitly negate the waveform.
Whether PHLEGM PCM is opposite in absolute polarity to a precisely identified NES-001 RCA-output reference. Speaker acoustic pressure cannot be inferred from software sample signs alone.
Impact: Code structure violates the project's definition-driven machine architecture, and missing hardware-stage polarity may complicate hardware waveform comparisons or phase-coherent mixing. It does not by itself explain low frame rate, incorrect audio pitch, or timing-related distortion.
02. Actual versus intended signal path
Observed in r82
Recommended architecture
y = −x reverses sample sign without reversing oscillator sequencing or changing frequency. The original NES output circuit, not an assumed speaker motion, is the proposed electrical reference.03. Reproducible source evidence
The excerpts below are transcribed from the inspected PHLEGM v9 r82 Full Archive Set. Line numbers identify their actual locations inside the archive; excerpts are shortened to the lines material to this issue.
A. The native APU mixer returns a positive-going sum
src/lib/native-support.bi · lines 1126–1134Dim dmcValue As Integer=gNativeApuDmcOutput(chipIndex) And &h7F
NativeApuEnsureMixerTables()
...
Dim mixed As Double=gNativeApuPulseMix(pulseIndex)+gNativeApuTndMix(tndIndex)
If mixed>1 Then mixed=1
Return mixed
Its tables use the familiar NESdev pulse and TND nonlinear DAC approximations (lines 1086–1107). This mixer is not inherently wrong: the lookup formulas describe output magnitude and DAC behavior, not the final console's absolute line-out polarity.
B. NES analog filters are hardwired into a generic library
src/lib/sound.bi · lines 60–70 and 451–462' NES front-panel/RCA analog reconstruction.
Const SOUND_NES_HP90_COEFFICIENT = 0.9873395160400396
Const SOUND_NES_HP440_COEFFICIENT = 0.9410087476560546
Const SOUND_NES_LP14K_COEFFICIENT = 0.7828654653395070
...
If nativeAudio Then
Dim hp90 As Double=SOUND_NES_HP90_COEFFICIENT* _
(gSoundNesHp90Output + mixed - gSoundNesHp90Input)
...
gSoundNesLp14kOutput += SOUND_NES_LP14K_COEFFICIENT* _
(hp440-gSoundNesLp14kOutput)
mixed=gSoundNesLp14kOutput
End If
Hardwire issue: The coefficients, NES-specific stage selection, and storage of its filter state reside in common host audio code rather than being selected from machine/chipset definitions. The nativeAudio condition derives from the presence of the nes-apu-io-v1 runtime (native-support.bi, lines 1137–1139), not an analog wiring profile.
C. PCM conversion preserves the final filter's sign
src/lib/sound.bi · lines 467–476Dim dcCoefficient As Double=0.995, deviceGain As Double=1.0
If gMachineAudioDevice=SOUND_DEVICE_PIEZO Then _
dcCoefficient=0.92: deviceGain=0.80
Dim filtered As Double=mixed-gSoundDcInput+ _
(dcCoefficient*gSoundDcOutput)
...
gSoundWaveData(bufferIndex,sampleIndex)=CShort(filtered*30000.0)
The common transducer model also contains hardcoded gain and coupling parameters. This last PCM assignment does not invert the signed waveform. There is likewise no explicit sign inversion in the inspected native sample queue or its sample-generation path.
D. The NES machine definition contains no analog polarity choice
cfg/machine/nintendo/NES-NTSC/machine.config.phlegm · lines 69–76audio_output_channels=1
audio_mix=mono
audio_device_default=internal speaker
apu_channels=pulse-1,pulse-2,triangle,noise,dmc
sound_enabled_default=true
sound_count=0
The definition describes audio routing and channel selection, but does not specify the console's analog stage, polarity, or filter topology. The support-chip definition supplies native_runtime=nes-apu-io-v1 rather than output-stage wiring.
04. Why this is an inconsistency
| Concern | Actual r82 behavior | Required separation |
|---|---|---|
| 2A03 DAC | Nonlinear digital-channel mix implemented in a reusable native runtime. | Keep the DAC algorithm independent from the motherboard's electrical output circuit. |
| Analog filters | NES 90 Hz / 440 Hz high-pass and 14 kHz low-pass constants embedded in sound.bi. | Make filter selection/parameters property of the selected output profile, not the generic host layer. |
| Polarity | No explicit inversion between native mixer and PCM emission. | Represent any hardware output inversion explicitly and apply it exactly once at the correct signal node. |
| Other machines | Generic sound code knows about a particular NES output circuit. | Retain reusable signal processing without applying NES-specific hardware assumptions to PET, SNES, or other machines. |
U9E) after the APU DAC signals are combined. That supports a hardware-stage inversion relative to that upstream node. It does not prove which sign should correspond to positive air pressure at an arbitrary user's speaker. The report targets output electrical waveform polarity relative to an identified NES-001 RCA measurement.05. Recommended definition-driven remediation
- Identify the output reference. Use a named motherboard revision (for example, NES-001), named output node (RCA audio) and a known stimulus. Confirm inversion using its schematic and, ideally, a recording captured with a known noninverting acquisition path.
- Declare analog wiring in
.phlegm. Let the machine specify which generic stage chain is attached to its APU (polarity, gain, coupling, and filter parameters). Do not embed NES board revisions or constants in the generic host audio library. - Reuse generic DSP primitives. Compile/load the chain when a machine or session is loaded, with state initialized on machine/reset boundaries. Run filtering and sign selection with minimal per-sample overhead.
- Apply inversion at the modeled hardware node. Invert the combined signal only after all signals that physically enter that stage have been summed; never reverse individual pulse/triangle/noise/DMC bit patterns. Avoid a second inversion in PCM export.
- Preserve unaffected machines. Define a noninverting default stage for profiles that do not declare one, and migrate existing machines explicitly rather than silently changing their audio.
Illustrative configuration — proposed keys, not existing syntax
# Proposed machine-config concept; parser support does NOT exist in r82:
audio_output_stage=generic-analog-v1
audio_output_polarity=inverted
audio_highpass_hz=90,440
audio_lowpass_hz=14000
audio_output_gain=1.0
Actual stage ordering, sample-rate coefficient calculation, and expansion-audio routing must be derived from the target hardware and integrated with the existing .phlegm descriptor/parser conventions. This sketch is intentionally not a drop-in patch.
Scope control: Treat channel synthesis, microcode sequencing, APU timers and cycle accounting as unrelated unless testing reveals a separate defect. A sign inversion should not be used to hide pitch, clipping or scheduling problems.
06. Verification and acceptance criteria
- Trace the sign: Capture deterministic, signed test samples before APU DAC output, immediately before the analog stage, after that stage, and just before PCM emission. Prove exactly one intentional sign change where configured.
- Reference hardware: Capture the same simple pulse/step test on a specified NES-001 at RCA out. Account for high-pass settling, DC offset, capture-system inversion, recording gain and any phase shift from filters. Compare waveform orientation, not only how it sounds.
- Check non-destructive behavior: Confirm that inversion does not change pitch, period, RMS magnitude beyond tolerance, channel envelopes, or frame/CPU/APU timing; the filtered waveform may differ while the test is switching stage models.
- Preserve all routed signals: Test native APU-only audio, any configured external audio mixing, and the expected cancellation/reinforcement relationships across a common analog stage.
- Cross-machine regression: Validate NES-NTSC, PET/CBM sound routes and machines without an APU. Check clean reset/session restore, output-device selection and silence behavior.
- Packaging and portability: Verify the same data-driven profile behavior on every affected Windows/Linux host backend; no hardware behavior should depend on graphics backend or word size.
No NES-specific analog coefficients or mandatory polarity assumptions remain in the generic host audio output path; machine definitions choose the appropriate processing chain.
NES electrical output waveform orientation agrees with the documented reference within an explicit measurement tolerance, and unrelated machines show no unintended sign changes.
Status: Source review completed; no executable build, analog measurement, patch, or regression test is claimed by this document.
07. Sources and provenance
Everything required to read this report is embedded in this file: styles, diagram, source excerpts and explanations. The optional links below are reference pointers for online follow-up.
- Inspected PHLEGM source:
PHLEGM-v9-r82-Full-Archive-Set-Text-Newline-Normalization-2026-1024-1525-3132.zip; SHA-2566c25d8c5742cd01882f5bcdbb6ca7d07bdfe9cbdf452ef7d3b87f1b5ba7ddbdb. Relevant archive paths and line numbers appear in Section 03. - NESdev Wiki, APU Mixer: defines the nonlinear
pulse_out + tnd_outapproximation used to interpret the source code. www.nesdev.org/wiki/APU_Mixer. - NES-001 board schematic, RetroTechCollection: documents the audio mixing and output network near the inverting
U9Estage. retrotechwiki.com/NES-001_Schematic. This schematic describes a particular console model; it is not a universal assertion about all NES/Famicom revisions. - NES schematics, independently traced: github.com/schenkzoola/NES; includes NES-001 and HVC-001 references.
- NESdev, MMC5 audio polarity: useful distinction between waveform-generator logic and inverting a completed analog signal. forums.nesdev.org/viewtopic.php?t=11432. This is background, not proof of the NES-001 line-out polarity by itself.
Final disposition: The hardwired analog-path inconsistency is confirmed by source inspection. The missing explicit inverter is also confirmed in the inspected software path; labeling its output definitively “wrong polarity” remains pending reference electrical measurement. The recommended fix is to model output-stage wiring in data and execute it through a reusable audio pipeline.